﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using PS.WSSDeploy.Client;
using PS_WSSDeploy_Package.Application;
using PS_WSSDeploy_Package.Client;
using PS_WSSDeploy_Package.Utils;
using PS_WSSDeploy_Package.Settings;

namespace PS_WSSDeploy_Package.WdCommand
{
    public class CommandResultCounter
    {
        public int Succeeded { get; set; }

        public int Failed { get; set; }
    }

    public abstract class BaseCmd : IWdCmd, ICmdResult
    {
        private static readonly TaskQueue _TaskQueue = new TaskQueue();

        public static CommandResultCounter ResultCounter { get; set; }
        
        protected ClientContext Cc
        {
            get
            {
                return new ClientContext(IsSharePointSandboxProject, SolutionPath, this);
            }
        }

        protected ConfigContainer ConfigContainer
        {
            get
            {
                return Cc.ConfigContainer;
            }
        }

        protected Config ActiveConfig
        {
            get
            {
                return ConfigContainer.GetActiveConfig(IsSharePointSandboxProject);
            }
        }

        private static Project CurrentProject { get; set; }
        private static ProjectItem CurrentProjectItem { get; set; }

        public static string ProjectName
        {
            get
            {
                if (CurrentProject == null)
                {
                    throw new InvalidDataException(WssDeployResources.BaseCmd_CommandProjectIsNull);
                }

                return CurrentProject.Name;
            }
        }

        public static string ProjectFullName
        {
            get
            {
                if (CurrentProject == null)
                {
                    throw new InvalidDataException(WssDeployResources.BaseCmd_CommandProjectIsNull);
                }

                return CurrentProject.FullName;
            }
        }

        public static string ProjectPath
        {
            get
            {
                if (CurrentProject == null)
                {
                    throw new InvalidDataException(WssDeployResources.BaseCmd_CommandProjectIsNull);
                }

                return Path.GetDirectoryName(CurrentProject.FullName);
            }
        }

        public static string SolutionPath
        {
            get
            {
                return DTEManager.Instance.SolutionPath;
            }
        }

        public static string ProjectItemPath
        {
            get
            {
                if (CurrentProjectItem != null)
                {
                    return CurrentProjectItem.get_FileNames(0);
                }
                return string.Empty;
            }
        }

        public static List<WdProjectItem> SelectedWdProjectItems
        {
            get
            {
                var ret = new List<WdProjectItem>();
                if (CurrentProjectItem != null)
                {
                    var items = DTEManager.Instance.GetSelectedProjectItems();
                    foreach (var item in items)
                    {
                        ret.Add(new WdProjectItem(item));
                    }
                }
                return ret;
            }
        }

        public static string ProjectTargetPath
        {
            get
            {
                var outputFileName = (string)CurrentProject.Properties.Item("OutputFileName").Value;
                return Path.Combine(ProjectTargetFolder, outputFileName);
            }
        }

        public static string ProjectTargetFolder
        {
            get
            {
                if (CurrentProject == null)
                {
                    throw new InvalidDataException(WssDeployResources.BaseCmd_CommandProjectIsNull);
                }

                var configuration = CurrentProject.ConfigurationManager.ActiveConfiguration;
                if (configuration == null)
                {
                    throw new InvalidDataException(WssDeployResources.BaseCmd_ActiveConfigurationIsNull);
                }

                var fullPath = (string)CurrentProject.Properties.Item("FullPath").Value;
                var outputPath = (string)configuration.Properties.Item("OutputPath").Value;
                return Path.Combine(fullPath, outputPath);
            }
        }

        public static string ProjectAssemblyFullName
        {
            get
            {
                var assemblyName = AssemblyName.GetAssemblyName(ProjectTargetPath);
                return assemblyName.FullName;
            }
        }

        public static string WSPFileName
        {
            get
            {
                var ret = IsSharePointProject
                          ? EnsureWSPFileName()
                          : ProjectName + Utils.Constants.WspExt;
                return ret;
            }
        }

        protected static string WSPFullFileName
        {
            get
            {
                var ret = IsSharePointProject
                    ? EnsureWSPFullFileName()
                    : Path.Combine(ProjectPath, WSPFileName);
                return ret;
            }
        }

        protected static string RootFolder
        {
            get
            {
                if (Directory.Exists(Path.Combine(ProjectPath, Utils.Constants.Root12Name)))
                {
                    return Utils.Constants.Root12Name;
                }
                if (Directory.Exists(Path.Combine(ProjectPath, Utils.Constants.Root14Name)))
                {
                    return Utils.Constants.Root14Name;
                }
                return "";
            }
        }

        protected static string RootFolderPath
        {
            get
            {
                return Path.Combine(ProjectPath, RootFolder);
            }
        }

        protected static string GACFolderPath
        {
            get
            {
                return Path.Combine(ProjectPath, "GAC");
            }
        }

        protected string BuildHeader
        {
            get
            {
                return string.Format(WssDeployResources.BaseCmd_WSSDeployStarted
                    , ProjectName
                    , ActiveConfig.ServerName
                    );
            }
            set { throw new System.NotImplementedException(); }
        }

        protected static bool ProjectItemIsLocatedAtRootFolder
        {
            get
            {
                return !string.IsNullOrEmpty(RootFolder) && ProjectItemPath.Contains(string.Format("\\{0}\\", RootFolder));
            }
        }

        protected static bool IsLocatedAtRootFolder(string projectItemPath)
        {
            return !string.IsNullOrEmpty(RootFolder) && projectItemPath.Contains(string.Format("\\{0}\\", RootFolder));
        }

        protected static RootFile GetRootFile(string projectItemFullPath)
        {
            return new RootFile
                       {
                           Path = projectItemFullPath,
                           DeploymentPath =
                               projectItemFullPath.Substring(projectItemFullPath.IndexOf(RootFolder) + 3)
                       };
        }

        protected static bool IsSharePointProject
        {
            get
            {
                return SharePointProjectManager.IsSharePointProject(ProjectFullName);
            }
        }

        protected static bool IsSharePointSandboxProject
        {
            get
            {
                return SharePointProjectManager.IsSharePointSandboxProject(ProjectFullName);
            }
        }

        static BaseCmd()
        {
            ResultCounter = new CommandResultCounter();
        }

        protected static void AddTask(IWdTask task)
        {
            _TaskQueue.Enqueue(task);
        }

        private static void ClearAllTasks()
        {
            _TaskQueue.Clear();
        }

        protected static void ClearResultCounter()
        {
            ResultCounter.Succeeded = 0;
            ResultCounter.Failed = 0;
        }

        public void Callback(object sender, EventArgs e)
        {
            Execute();
        }

        public virtual void Execute()
        {
            ClearAllTasks();

            CurrentProject = DTEManager.Instance.WorkedProject;
            CurrentProjectItem = DTEManager.Instance.WorkedProjectItem;

            if (CurrentProject == null || CurrentProject.FullName.Length == 0)
            {
                DTEManager.Instance.StartNewBuildWindow();
                WriteOutput(WssDeployResources.BaseCmd_NotSelectedWorkingProject);
                return;
            }

            if (CurrentProject.FullName.Length > 0 && DoCheckExistConfig())
            {
                ClearResultCounter();
                DoPreExecute();
                DoExecute();
                DoPostExecute();
            }
        }

        public abstract void DoExecute();

        public virtual bool DoCheckExistConfig()
        {
            if (!ConfigContainer.Exists(SolutionPath) || ActiveConfig == null)
            {
                var settingForm = new SettingForm(IsSharePointSandboxProject, Cc, SolutionPath);
                return (DialogResult.OK == settingForm.ShowDialog());
            }
            return true;
        }

        public virtual void DoPreExecute()
        {
            DTEManager.Instance.StartNewBuildWindow();
            DTEManager.Instance.WriteBuildWindow(BuildHeader);
        }

        public virtual void DoPostExecute()
        {
            AddTask(new WriteResultTask());
        }

        protected virtual vsCommandStatus Status()
        {
            var result = vsCommandStatus.vsCommandStatusNinched | vsCommandStatus.vsCommandStatusSupported;
            if (DTEManager.Instance.Application.Solution.IsOpen)
            {
                result = vsCommandStatus.vsCommandStatusEnabled | vsCommandStatus.vsCommandStatusSupported;
            }
            return result;
        }

        class WriteResultTask : IWdTask
        {
            public void TaskExecute()
            {
                var counter = BaseCmd.ResultCounter;
                DTEManager.Instance.WriteBuildWindow(
                    string.Format(WssDeployResources.BaseCmd_RunSucceeded
                    , counter.Succeeded, counter.Failed));
            }
        }

        protected void Build()
        {
            DTEManager.Instance.Application.Solution.SolutionBuild.Build(true);
        }

        protected void BuildPackage()
        {
            SharePointProjectManager.BuildPackage(ProjectFullName);
        }

        public void WriteOutput(string msg)
        {
            DTEManager.Instance.WriteBuildWindow(msg);
        }

        public void SetSuccess()
        {
            ++ResultCounter.Succeeded;
        }

        public void SetFailed()
        {
            ++ResultCounter.Failed;
        }

        private static string EnsureWSPFileName()
        {
            var wspFileName = SharePointProjectManager.GetWspName(ProjectFullName);
            if(string.IsNullOrEmpty(wspFileName))
            {
                wspFileName = ProjectName + Utils.Constants.WspExt;
            }
            return wspFileName;
        }

        private static string EnsureWSPFullFileName()
        {
            var wspFullFileName = SharePointProjectManager.GetWspFullPath(ProjectFullName);
            if(!File.Exists(wspFullFileName))
            {
                wspFullFileName = Path.Combine(ProjectTargetFolder, WSPFileName);
            }
            return wspFullFileName;
        }

        public static void DisableForSandbox(object sender, EventArgs e)
        {
            CurrentProject = DTEManager.Instance.WorkedProject;
            CurrentProjectItem = DTEManager.Instance.WorkedProjectItem;

            if (sender is OleMenuCommand)
            {
                (sender as OleMenuCommand).Enabled = !IsSharePointSandboxProject;
            }
        }

        protected static void AddCommandToMenu(OleMenuCommandService menuCmdService, BaseCmd cmd, CommandID cmdId, bool enableForSandbox)
        {
            var menuCmd = new OleMenuCommand(cmd.Callback, cmdId);
            if (!enableForSandbox)
            {
                menuCmd.BeforeQueryStatus += DisableForSandbox;
            }
            menuCmdService.AddCommand(menuCmd);
        }
    }
}
